/*
 * Topic: 雕塑（Sculpture）
 * Author: Yuanshun L
 * Written: 6-Nov-2021
 * Method: 离散化和广度优先算法
 */

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<queue>

using namespace std;


#define maxn 50 + 5 // 离散化后点的个数
#define maxc (1000 + 5) // 非离散化的范围，注意加括号

int x0[maxn],x1[maxn],y0[maxn],y1[maxn],z0[maxn],z1[maxn];
int color[maxn*2][maxn*2][maxn*2];
int xs[maxn*2],ys[maxn*2],zs[maxn*2];

int nx,ny,nz; // 离散化后x,y,z的个数

// x,y,z方向上值的变化
int dx[] = {1,-1,0,0,0,0};
int dy[] = {0,0,1,-1,0,0};
int dz[] = {0,0,0,0,1,-1};

struct Cell{
    int x,y,z;
    Cell(int x=0,int y=0,int z=0):x(x),y(y),z(z){}
    Cell neighbor(int dir){ // 返回某个方向的邻结点
        return Cell(x+dx[dir],y+dy[dir],z+dz[dir]);
    }
    bool valid(){ // 是否包含空间，不考虑边上最大值
        return x>=0 && x <nx-1 && y>=0 && y<ny-1 && z>=0 && z<nz-1;
    }
    bool solid(){ // 是否着色
        return color[x][y][z] == 1;
    }
    void setVisited(){ // 标记已经访问
        color[x][y][z] = 2;
    }
    bool isVisited(){ // 是否被访问了
        return color[x][y][z] == 2;
    }
    int volume(){ // 返回体积
        return (xs[x+1] - xs[x]) * (ys[y+1]-ys[y]) * (zs[z+1]- zs[z]);
    }
    int area(int dir){ // 返回面积
        if(dx[dir]) return (ys[y+1]-ys[y]) * (zs[z+1]- zs[z]);
        else if(dy[dir]) return (xs[x+1] - xs[x])*(zs[z+1]- zs[z]);
        return (xs[x+1] - xs[x]) * (ys[y+1]-ys[y]);
    }
};

// 离散化
void discrete(int *arr, int &n){
    sort(arr,arr+n);
    n = unique(arr,arr+n) - arr;
}

// 拿到一个值在数组中的下标
int getId(int *arr,int n, int v){
    return lower_bound(arr,arr+n,v) - arr;
}

// 得到体积和面积
void solve(int &v,int &s){
    v=s=0;

    queue<Cell> q;

    Cell c;
    c.setVisited();
    q.push(c);

    // 广度优先遍历边缘连通空白区域
    while(!q.empty()){
        c = q.front();q.pop();
        v += c.volume(); // 外围空白区域的体积
        for(int dir=0;dir<6;dir++){
            Cell nb = c.neighbor(dir);
            if(!nb.valid()) continue;

            if(nb.solid()) // 已经着色，找到一个实体块
                s+= nb.area(dir);
            else if(!nb.isVisited()){ // 没有被访问而且没有着色
                nb.setVisited();
                q.push(nb);
            }
        }
    }
    v= maxc*maxc*maxc - v;
}

int main(){

    freopen("data.in","r",stdin);
    freopen("data.out","w",stdout);

    // 读取数据
    int T;
    scanf("%d",&T);

    // 遍历T个方案
    while(T--){

        nx = ny = nz = 2;
        xs[0] = ys[0] = zs[0] = 0;
        xs[1] = ys[1] = zs[1] = maxc;

        int n,i=0; // 立方块的数量
        scanf("%d",&n);

        for(i=0;i<n;i++){
            scanf("%d%d%d%d%d%d",&x0[i],&y0[i],&z0[i],&x1[i],&y1[i],&z1[i]);
            x1[i] += x0[i]; y1[i] += y0[i]; z1[i] += z0[i];
            xs[nx++] = x0[i]; xs[nx++] = x1[i];
            ys[ny++] = y0[i]; ys[ny++] = y1[i];
            zs[nz++] = z0[i]; zs[nz++] = z1[i];
        }

        // 离散化
        discrete(xs,nx);
        discrete(ys,ny);
        discrete(zs,nz);


        // 着色
        memset(color,0,sizeof(color));
        for(i=0;i<n;i++){
            int X1,Y1,Z1,X2,Y2,Z2;
            X1 = getId(xs,nx,x0[i]); X2 = getId(xs,nx,x1[i]);
            Y1 = getId(ys,ny,y0[i]); Y2 = getId(ys,ny,y1[i]);
            Z1 = getId(zs,nz,z0[i]); Z2 = getId(zs,nz,z1[i]);
            
            // 注意下面三个循环的结束条件中的关系运算符都是小于，而不是小于等于
            for(int k1=X1;k1<X2;k1++)
                for(int k2=Y1;k2<Y2;k2++)
                    for(int k3=Z1;k3<Z2;k3++)
                        color[k1][k2][k3] = 1;
        }

        int area,volume;
        solve(volume,area);
        cout<< area << " "<< volume << endl;
    }

    return 0;
}